package com.wstuo.common.config.onlinelog.aop;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.InvocationTargetException;
import java.util.Date;

import javax.servlet.http.HttpSession;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.log4j.Logger;
import org.apache.logging.log4j.Level;
import org.apache.struts2.ServletActionContext;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.context.ApplicationContext;

import com.wstuo.common.config.onlinelog.dto.UserErrLogDTO;
import com.wstuo.common.config.onlinelog.entity.UserOptLog;
import com.wstuo.common.config.onlinelog.service.IUserErrLogService;
import com.wstuo.common.config.onlinelog.service.IUserOptLogServiceUtil;
import com.wstuo.common.dto.AnnotationPropertyDTO;
import com.wstuo.common.security.dto.UserDTO;
import com.wstuo.common.security.service.IUserInfoService;
import com.wstuo.common.security.utils.AppConfigUtils;
import com.wstuo.common.util.AppliactionBaseListener;
import com.wstuo.common.util.LogUtils;
import com.wstuo.common.util.StringUtils;
import com.wstuo.common.util.TimeUtils;
import com.wstuo.multitenancy.TenantIdResolver;

/***
 * UserOptLogAspect Class.
 * 
 * @author spring date 2010-10-11
 */

public class UserOptLogAspect {
	private static final Logger LOGGER = Logger
			.getLogger(UserOptLogAspect.class);
	@Autowired
	private IUserOptLogServiceUtil useroptlogService;
	@Autowired
	private IUserErrLogService userErrLogService;
	@Autowired
	private IUserInfoService userInfoService;
//	@Autowired
//	private ICache cacheService;
	
	
	/**
	 * Username
	 */
	public String getUsername() {
		String username = "Unknown user";

		if (SecurityContextHolder.getContext().getAuthentication() != null) {
			Object principal = SecurityContextHolder.getContext()
					.getAuthentication().getPrincipal();

			if (principal instanceof UserDetails) {
				username = ((UserDetails) principal).getUsername();
			} else {
				username = principal.toString();
			}
		}

		return username;
	}

	public UserDTO getCurrentUser() {
		UserDTO dto = new UserDTO();
		if (SecurityContextHolder.getContext().getAuthentication() != null) {
			Object principal = SecurityContextHolder.getContext()
					.getAuthentication().getPrincipal();

			if (principal instanceof UserDetails) {
				dto = ((UserDTO) principal);
			}
		}
		return dto;
	}

	/**
	 * DtoId
	 */
	public Long getDtoId(Object[] args) throws IllegalAccessException,
			InvocationTargetException, NoSuchMethodException {
		Long dtoId = null;
		if (args.length == 1) {
			Object arg = args[0];

			// add mars @20110630
			AnnotationPropertyDTO adto = null;

			if (arg != null) {
				adto = arg.getClass().getAnnotation(AnnotationPropertyDTO.class);
			}
			if (adto != null) {
				String idName = adto.id();
				if (PropertyUtils.getSimpleProperty(arg, idName)==null || PropertyUtils.getSimpleProperty(arg, idName).toString().indexOf(".")>-1) {
					dtoId = 0L;
				}else{
					dtoId = (Long)PropertyUtils.getSimpleProperty(arg, idName);
				}
				
			} else if (arg instanceof Long) {
				dtoId = (Long) arg;
			}
		}
		return dtoId;
	}

	/**
	 * 
	 * Around( EDP )
	 * */
	@SuppressWarnings("unused")
	public Object around(ProceedingJoinPoint jp) throws Throwable {

		Object obj = null;
		long execTime = 0;
		String methodName = jp.getSignature().getName();

		String resourceName = jp.getTarget().getClass().getName();
		if (resourceName.endsWith("Service")) {
			int s = resourceName.lastIndexOf(".") + 1;
			int e = resourceName.lastIndexOf("Service");
			resourceName = resourceName.substring(s, e);
		}
		Long dtoId = null;
		try {
			dtoId = getDtoId(jp.getArgs());
		} catch (Exception e) {
			e.printStackTrace();
			LOGGER.error(e.getMessage());
		}

		StringWriter sw = null;
		ApplicationContext ctx = AppliactionBaseListener.ctx;
		try {
			long begin = System.currentTimeMillis();
			obj = jp.proceed();
			long end = System.currentTimeMillis();
			execTime = end - begin;
		} catch (Exception e) {
			throw e;
		} finally {
			if (methodName.indexOf("findPagerIM") == -1
					&& methodName.indexOf("attributeValue2String") == -1) {

				HttpSession session = null;

				try {
					session = ServletActionContext.getRequest().getSession();
				} catch (Exception ex) {
					LOGGER.info("This operator my be system");
				}
				String tenantId = TenantIdResolver.getInstance().getDefaultTenantId();
				String filePath =  AppConfigUtils.getInstance().getDefaultOptLogPath();
	    		if( !"Unknown user".equals(getUsername()) && !("anonymousUser").equals(getUsername()) ){
	    			/*
	    			Object cacheValue = cacheService.getValue(getUsername());
		    		if(cacheValue!=null){
		    			tenantId = cacheValue.toString();
		    		}else{
		    			LOGGER.error("Key:"+getUsername()+",can not find tenantId!");
		    		}*/
		    		filePath =  AppConfigUtils.getInstance().getOptLogPath(tenantId);
	    		}
	    		String resId = "0";
	    		if(null != dtoId){
	    			resId = dtoId.toString();
	    		}
	    		filePath = filePath + "/userOptLog.csv";
	    		String loggerName = "userOptLog"+tenantId;
				String date = TimeUtils.format(new Date(), TimeUtils.DATETIME_PATTERN);
				org.apache.logging.log4j.Logger logger = LogUtils.getUserOptLogger(filePath, getUsername(), methodName, resourceName, date,
						execTime,resId,loggerName);
				logger.log(Level.INFO, "");
			}
		}
		return obj;
	}

	/**
	 * LogUserOpt // @After(EDP)
	 */

	public void logUserOpt(JoinPoint jp) {
		String methodName = jp.getSignature().getName();
		String resourceName = jp.getTarget().getClass().getName();
		if (resourceName.endsWith("Service")) {
			int s = resourceName.lastIndexOf(".") + 1;
			int e = resourceName.lastIndexOf("Service");
			resourceName = resourceName.substring(s, e);
		}
		Long dtoId = null;
		try {
			dtoId = getDtoId(jp.getArgs());
		} catch (Exception e) {
			LOGGER.error(e.getMessage());
		}
		UserOptLog log = new UserOptLog();
		log.setUserName(getUsername());
		log.setTime(new Date());
		log.setMethodName(methodName);
		log.setResourceName(resourceName);
		log.setResourceId(dtoId);
		if (StringUtils.hasText(log.getUserName())
				&& !"Unknown user".equals(log.getUserName())) {
			UserDTO userDTO = userInfoService.findUserByName(log.getUserName());
			if (userDTO != null) {
				log.setUserFullName(userDTO.getFullName());
			}

		}
		HttpSession session = null;

		try {
			session = ServletActionContext.getRequest().getSession();
		} catch (Exception ex) {
			LOGGER.error(ex);
		}

		if ((session != null)
				&& (session.getAttribute("userCompanyNo") != null)) {
			Long companyNo = (Long) session.getAttribute("userCompanyNo");
			log.setCompanyNo(companyNo);
		}

		if (methodName.indexOf("findPagerIM") == -1) {
			useroptlogService.saveUserOptLog(log);
		}
	}

	// @AfterThrowing( pointcut = EDP, throwing = "ex" )
	public void logException(JoinPoint jp, Exception ex) {
		String methodName = jp.getSignature().getName();
		String resourceName = jp.getTarget().getClass().getName();

		if (resourceName.endsWith("Service")) {
			int s = resourceName.lastIndexOf(".") + 1;
			int e = resourceName.lastIndexOf("Service");
			resourceName = resourceName.substring(s, e);
		}

		Long dtoId = null;

		try {
			dtoId = getDtoId(jp.getArgs());
		} catch (Exception e) {
			LOGGER.error(e.getMessage());
		}

		UserErrLogDTO log = new UserErrLogDTO();
		log.setUserName(getUsername());
		log.setTime(new Date());
		log.setMethodName(methodName);
		log.setResourceName(resourceName);
		log.setResourceId(dtoId);
		if ((null != ex) && (ex.getCause() != null)) {
			log.setErrMsg(ex.getMessage());
			StringWriter sw = new StringWriter();
			PrintWriter pw = new PrintWriter(sw);
			LOGGER.error(ex.getMessage());
			log.setErrCause(sw.getBuffer().toString());
			try {
				if(pw!=null){
					pw.flush();
					pw.close();
				}
				if(sw!=null){
					sw.flush();
					sw.close();
				}
			} catch (IOException e) {
				LOGGER.error(e);
			}
		}
		userErrLogService.saveUserErrLog(log);
	}
}
